/*
 *  TUIO_receiver.c
 *
 *  This code monitors OSC messages received with the TUIO protocol
 *  and dispatches it to the appropriate handlers.
 *
 *  Copyright (C) 2010 LIMSI-CNRS (Orsay-France) and EFREI (Paris-France)
 *
 *  Authors: Rami Ajaj, Nicolas Flasque and Frederic Vernier.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation; either version 2.1 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  $Id$
 */

#include "TUIO_receiver.h"

int done = 0;

int TUIO_receiver(char* input_port, t_applicationData *p_appData)
{
  int lo_fd;
  fd_set rfds;
  struct timeval tv;
  int retval;

  void *userData = (void *)p_appData;

  /* start a new server on port TUIO_IN_PORT */
  lo_server s = lo_server_new(input_port, error);

  /* add method that will match any path and args */
  /* this method will handle source, alive and fseq messages*/
  lo_server_add_method(s, NULL, NULL, generic_handler, userData);

  /* the following methods will handle set messages according to the format */

  /* add method that will matchs /tuio/2Dcur set s x y X Y m */
  lo_server_add_method(s, "/tuio/2Dcur", "sifffff", tuio2Dcur_handler, userData);

  /* add method that will matchs /tuio/25Dcur set s x y z X Y Z m */
  lo_server_add_method(s, "/tuio/25Dcur", "sifffffff", tuio25Dcur_handler, userData);

  /* add method that will matchs /tuio/3Dcur set s x y z X Y Z m */
  lo_server_add_method(s, "/tuio/3Dcur", "sifffffff", tuio3Dcur_handler, userData);

	/* add method that will matchs /tuio/2Dobj set s i x y a X Y A m r */
  lo_server_add_method(s, "/tuio/2Dobj", "siiffffffff", tuio2Dobj_handler, userData);

  /* add method that will matchs /tuio/25Dobj set s i x y z a X Y Z A m r */
  lo_server_add_method(s, "/tuio/25Dobj", "siiffffffffff", tuio25Dobj_handler, userData);

  /* add method that will matchs /tuio/3Dobj set s i x y z a b c X Y Z A B C m r */
  lo_server_add_method(s, "/tuio/3Dobj", "siiffffffffffffff", tuio3Dobj_handler, userData);

	/* add method that will matchs /tuio/2Dblb set s x y a w h f X Y A m r */
  lo_server_add_method(s, "/tuio/2Dblb", "sifffffffffff", tuio2Dblb_handler, userData);

  /* add method that will matchs /tuio/25Dblb set s x y z a w h f X Y Z A m r */
  lo_server_add_method(s, "/tuio/25Dblb", "sifffffffffffff", tuio25Dblb_handler, userData);

  /* add method that will matchs /tuio/3Dblb set s x y z a b c w h d v X Y Z A B C m r */
  lo_server_add_method(s, "/tuio/3Dblb", "siffffffffffffffffff", tuio3Dblb_handler, userData);



  /* get the file descriptor of the server socket, if supported */
  lo_fd = lo_server_get_socket_fd(s);

  if (lo_fd > 0) {

    /* select() on lo_server fd is supported, so we'll use select()
     * to watch both stdin and the lo_server fd. */

    do {
      FD_ZERO(&rfds);
#ifndef WIN32
      FD_SET(0, &rfds);  /* stdin */
#endif
      FD_SET(lo_fd, &rfds);

      retval = select(lo_fd + 1, &rfds, NULL, NULL, NULL); /* no timeout */

      if (retval == -1) {

        printf("select() error\n");
        exit(1);

      } else if (retval > 0) {

        if (FD_ISSET(0, &rfds)) {

          read_stdin();

        }
        if (FD_ISSET(lo_fd, &rfds)) {

          lo_server_recv_noblock(s, 0);

        }
      }

    } while (!done);

  } else {

    /* lo_server protocol does not support select(), so we'll watch
     * stdin while polling the lo_server. */
#ifdef WIN32
    printf("non-blocking input from stdin not supported under Windows\n");
    exit(1);
#else
    do {

      FD_ZERO(&rfds);
      FD_SET(0, &rfds);
      tv.tv_sec = 0;
      tv.tv_usec = 10000;

      retval = select(1, &rfds, NULL, NULL, &tv); /* timeout every 10ms */

      if (retval == -1) {

        printf("select() error\n");
        exit(1);

      } else if (retval > 0 && FD_ISSET(0, &rfds)) {

        read_stdin();

      }

      lo_server_recv_noblock(s, 0);

    } while (!done);
#endif
  }

  return 0;
}

void error(int num, const char *msg, const char *path)
{
  printf("liblo server error %d in path %s: %s\n", num, path, msg);
}


void read_stdin(void)
{
  char buf[256];
  int len = read(0, buf, 256);
  if (len > 0) {
    printf("stdin: ");
    fwrite(buf, len, 1, stdout);
    printf("\n");
    fflush(stdout);
  }
}


